//go:build linux || windows

// Websocket 插件
// Add By : 陈狍子 e4ting@qq.com 2024-07-24 22:22:04

package main

import (
	// "os"
	"bytes"
	"fmt"
	"log"

	// "errors"
	// "context"
	"encoding/json"
	"net/http"
	"net/url"

	"github.com/gorilla/websocket"

	"wick/internal/model"
)

var (
	ListenTo   string = "127.0.0.1:43210"
	PLUGIN_API string = "/api/plugin"
)

type CmdInfo struct {
	Param  any    `json:"param"`
	Action string `json:"action"`
}

type RespData struct {
	Code int    `json:"code"`
	Data any    `json:"data"`
	Msg  string `json:"msg"`
}

type PluginServer struct {
}

// func (s *PluginServer) SayHello(ctx context.Context, in *HelloRequest) (*HelloReply, error) {
// 	return &HelloReply{Message: "Hello " + in.Name}, nil
// }

func (self *PluginServer) Init() *PluginServer {
	return nil
}

func (self *PluginServer) Error(conn *websocket.Conn, e error, code int) {
	ret := RespData{
		Code: code,
		Msg:  e.Error(),
	}
	data, _ := json.Marshal(ret)
	conn.WriteMessage(websocket.TextMessage, data)
}

func (self *PluginServer) httpErrRes(w http.ResponseWriter, e error, code int) {
	ret := RespData{
		Code: code,
		Msg:  e.Error(),
	}
	data, _ := json.Marshal(ret)
	http.Error(w, string(data), 200)
}

func (self *PluginServer) CorePlugin(w http.ResponseWriter, r *http.Request) {
	var upgrader = websocket.Upgrader{
		ReadBufferSize:  1024,
		WriteBufferSize: 1024,
		CheckOrigin:     func(r *http.Request) bool { return true },
		// Fixed : https://www.cnblogs.com/alpiny/p/12788241.html
		Subprotocols: []string{r.Header.Get("Sec-WebSocket-Protocol")},
	}
	conn, err := upgrader.Upgrade(w, r, nil)
	if err != nil {
		log.Println(err)
		self.httpErrRes(w, err, 400)
		return
	}
	token, errr := url.QueryUnescape(r.Header.Get("Sec-WebSocket-Protocol"))
	log.Println(token, errr)
	for {
		messageType, receiveBytes, err := conn.ReadMessage()
		if err != nil {
			self.Error(conn, err, 500)
			return
		}
		switch messageType {
		case websocket.TextMessage:
			info := CmdInfo{}
			var resp RespData
			err := json.Unmarshal(receiveBytes, &info)
			if err != nil {
				self.Error(conn, err, 500)
				return
			}
			log.Printf("%+v", info)
			switch info.Action {
			case "info":
				resp = RespData{
					Code: 200,
					Data: func(param any) any {
						return node
					}(info.Param),
				}
			case "auth":
				resp = RespData{
					Code: 200,
					Data: func(param any) any {
						log.Println("客户端token:", token)
						return struct{}{}
					}(info.Param),
				}
			case "wamp":
				resp = RespData{
					Code: 200,
					Data: func(param any) any {
						return map[string]any{
							"caller": Registers,
							"topic":  Subscribers,
						}
					}(info.Param),
				}
			default:
				resp = RespData{
					Code: 404,
					Data: "未知方法",
				}
			}
			if ret, err := json.Marshal(resp); err != nil {
				self.Error(conn, err, 500)
				return
			} else {
				conn.WriteMessage(websocket.TextMessage, ret)
			}
		case websocket.PingMessage:
			conn.WriteMessage(websocket.PongMessage, []byte("pong"))
		case websocket.PongMessage:
			conn.WriteMessage(websocket.PingMessage, []byte("ping"))
		case websocket.CloseMessage:
			conn.Close()
			return
		}
	}
}

func (self *PluginServer) RunServer() error {
	http.HandleFunc(PLUGIN_API, self.CorePlugin)
	log.Println("start plugin server:", ListenTo)
	server := &http.Server{Addr: ListenTo}
	if err := server.ListenAndServe(); err != nil {
		log.Println(err)
		return err
	}
	log.Println("插件服务已退出")
	return nil
}

func ConnectServer() (result model.DeviceInfo, err error) {
	WSurl := fmt.Sprintf("ws://%s%s", ListenTo, PLUGIN_API)
	conn, _, err2 := websocket.DefaultDialer.Dial(WSurl, nil)
	if err2 != nil {
		err = err2
		// log.Fatal("连接错误:", err)
		return
	}
	defer conn.Close()

	ActionInfo := func() (result model.DeviceInfo, err error) {
		payload := dict{
			"action": "info",
			"param":  dict{},
		}
		// 发送消息
		jsonBytes, _ := json.Marshal(payload)
		err = conn.WriteMessage(websocket.TextMessage, jsonBytes)
		if err != nil {
			logger.Println("发送消息错误:", err)
			return
		}
		_, message, err1 := conn.ReadMessage()
		if err1 != nil {
			err = err1
			logger.Println("读取消息错误:", err)
			return
		}
		if err = json.NewDecoder(bytes.NewBuffer(message)).Decode(&result); err != nil {
			logger.Println("数据解析错误:", err)
			return
		}
		logger.Printf("设备基本信息: %+v", result)
		return
	}
	return ActionInfo()
}
